﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace iMario
{
    public abstract class GameObject : GameEntity
    {
        //Mục đích abstract class GameObject
        //  - Tập trung các thuộc tính và phương thức xử lí của các Object sử dụng trong Game

        //Danh sách các thuộc tính và ý nghĩa
        public const int LEFT = 4;                     //Hằng số cho hướng xét đụng độ trong hàm Collision
        public const int RIGHT = 6;                    //Hằng số cho hướng xét đụng độ trong hàm Collision
        public const int UP = 8;                       //Hằng số cho hướng xét đụng độ trong hàm Collision
        public const int DOWN = 2;                     //Hằng số cho hướng xét đụng độ trong hàm Collision

        //Danh sách các phương thức và ý nghĩa
        //Hàm nhân bản thêm đối tượng thuộc lớp đối tượng mà nó thuộc về và trả về chính đối tượng đã nhân bản thành công đó
        //  1. Tham số truyền vào: Không có
        //  2. Giá trị trả về:
        //      - Con trỏ GameEntity của đối tượng đã được nhân bản thành công
        public override GameEntity Clone()
        {
            return null;
        }

        //Hàm cập nhật trạng thái của đối tượng
        //  1. Tham số truyền vào:
        //      - KeyboardState _keyboard: biểu diễn trạng thái của bàn phím
        //      - MouseState _mouse: biểu diễn trạng thái chuột
        //      - GameTime _gameTime: thời gian của game
        //  2. Giá trị trả về: Không có
        public override void Update(KeyboardState _keyboard, MouseState _mouse, GameTime _gameTime)
        {
            //Do nothing here
        }

        //Hàm kiểm tra đụng độ giữa 2 đối tượng
        //  1. Tham số truyền vào:
        //      - Rectangle _object1: đại diện cho đối tượng thứ nhất
        //      - Rectangle _object2: đại diện cho đối tượng thứ hai
        //      - int _direct: Hướng đụng độ tiếp theo cần kiểm tra, theo các phương trên phần numpad của bàn phím (2, 4, 6, 8)
        //  2. Giá trị trả về: bool
        //      - True: xảy ra đụng độ
        //      - False: không xảy ra đụng độ 
        public bool Collision(Rectangle _object1, Rectangle _object2, int _way)
        {
            //Hướng xử lí:
            //Kiểm tra từng trường hợp của _direct

        
            //Tiến hành
            //Kiểm tra từng trường hợp của _direct
            switch (_way)
            {
                //Hướng cần kiểm tra đụng độ là bên dưới
                //  Object1 nằm trên Object2
                case DOWN:
                    {
                        if ((_object1.Y + _object1.Height >= _object2.Y)
                            && (_object1.Y + _object1.Height <= _object2.Y + _object2.Height))
                            return true;

                        break;
                    }

                //Hướng cần kiểm tra là bên trái
                //  Object 1 nằm bên phải Object2
                case LEFT:
                    {
                        if ((_object1.X <= _object2.X + _object2.Width)
                            && (_object1.X >= _object2.X))
                            return true;

                        break;
                    }

                //Hướng kiểm tra là bên phải
                //  Object1 nằm bên trái Object2
                case RIGHT:
                    {
                        if ((_object1.X + _object1.Width >= _object2.X)
                            && (_object1.X + _object1.Width <= _object2.X + _object2.Width))
                            return true;

                        break;
                    }

                //Hướng kiểm tra là bên trên
                //Object1 nằm bên dưới Object2
                case UP:
                    {
                        if ((_object1.Y <= _object2.Y + _object2.Height)
                            && (_object1.Y >= _object2.Y))
                            return true;

                        break;
                    }
            }

            return false;
        }

        //Hàm kiểm tra đụng độ giữa 1 đối tượng và bản đồ
        //  1. Tham số truyền vào:
        //      - Rectangle _object: Đại diện cho đối tượng (nhân vật, quái vật, đạn)
        //      - Map _map: Đại diện cho bản đồ đang được sử dụng
        //      - int _way: Đại diện cho hướng cần xét đụng độ
        //  2. Giá trị trả về: bool
        //      - True: xảy ra đụng độ
        //      - False: không xảy ra đụng độ
        public bool Collision(Rectangle _object, Map _map, int _way)
        { 
            //Hướng xử lí
            //  1. Kiểm tra từng trường hợp _way

            //Tiến hành:
            //  1. Kiểm tra từng trường hợp _way
            switch (_way)
            {
                case LEFT:
                    {
                        //Lấy tọa độ góc trên-trái và dưới-phải
                        Point _top_left = new Point((_object.X) / Map.TileSize, _object.Y / Map.TileSize);
                        Point _bottom_right = new Point((_object.X + _object.Width) / Map.TileSize, (_object.Y + _object.Height - 5) / Map.TileSize);

                        if (_top_left.X == _bottom_right.X)
                        {


                            if (_map.mapMatrix[_top_left.Y - 1][_top_left.X] == 43)
                                _map.mapMatrix[_top_left.Y - 1][_top_left.X] = _map.nTile + 1;

                            if ((_map.mapMatrix[_top_left.Y - 1][_top_left.X] > 0) && (_map.mapMatrix[_top_left.Y - 1][_top_left.X] < _map.nTile)
                                && (_map.mapMatrix[_top_left.Y - 1][_top_left.X] != _map.nTile - 3))
                            {
                                return true;
                            }
                        }
                        else
                        {
                            for (int row = _top_left.Y; row <= _bottom_right.Y; row++)
                            {
                                if (_map.mapMatrix[row][_top_left.X] == 43)
                                    _map.mapMatrix[row][_top_left.X] = _map.nTile + 1;

                                if ((_map.mapMatrix[row][_top_left.X] > 0) && (_map.mapMatrix[row][_top_left.X] < _map.nTile)
                                    && (_map.mapMatrix[row][_top_left.X] != _map.nTile - 3))
                                {
                                    return true;
                                }
                            }
                        }

                        break;
                    }
                case RIGHT:
                    {
                        //Lấy tọa độ góc trên-trái và dưới-phải
                        Point _top_left = new Point((_object.X) / Map.TileSize, _object.Y / Map.TileSize);
                        Point _bottom_right = new Point((_object.X + _object.Width) / Map.TileSize, (_object.Y + _object.Height - 5) / Map.TileSize);

                        if (_bottom_right.X == _top_left.X)
                        {
                            if (_map.mapMatrix[_bottom_right.Y - 1][_bottom_right.X] == 43)
                                _map.mapMatrix[_bottom_right.Y - 1][_bottom_right.X] = _map.nTile + 1;

                            if ((_map.mapMatrix[_bottom_right.Y - 1][_bottom_right.X] > 0) && (_map.mapMatrix[_bottom_right.Y - 1][_bottom_right.X] < _map.nTile)
                                && (_map.mapMatrix[_bottom_right.Y - 1][_bottom_right.X] != _map.nTile - 3))
                                return true;
                        }
                        else
                        {
                            for (int row = _top_left.Y; row <= _bottom_right.Y; row++)
                            {
                                if (_map.mapMatrix[row][_bottom_right.X] == 43)
                                    _map.mapMatrix[row][_bottom_right.X] = _map.nTile + 1;

                                if ((_map.mapMatrix[row][_bottom_right.X] > 0) && (_map.mapMatrix[row][_bottom_right.X] < _map.nTile)
                                    && (_map.mapMatrix[row][_bottom_right.X] != _map.nTile - 3))
                                    return true;
                            }
                        }

                        break;
                    }
                case UP:
                    {
                        //Lấy tọa độ các góc trên-trái và dưới-phải
                        Point _top_left = new Point((_object.X) / Map.TileSize, _object.Y / Map.TileSize);
                        Point _bottom_right = new Point((_object.X + _object.Width) / Map.TileSize, (_object.Y + _object.Height) / Map.TileSize);

                        if (_top_left.X == _bottom_right.X)
                        {
                            if (_map.mapMatrix[_top_left.Y][_top_left.X] == 43)
                                _map.mapMatrix[_top_left.Y][_top_left.X] = _map.nTile + 1;

                            if ((_map.mapMatrix[_top_left.Y][_top_left.X] > 0) && (_map.mapMatrix[_top_left.Y][_top_left.X] < _map.nTile)
                                && (_map.mapMatrix[_top_left.Y][_top_left.X] != _map.nTile - 3))
                            {
                                switch (_map.mapMatrix[_top_left.Y][_top_left.X])
                                {
                                    case 40:
                                        {
                                            _map.mapMatrix[_top_left.Y][_top_left.X] = 42;

                                            break;
                                        }
                                    case 41:
                                        {
                                            _map.mapMatrix[_top_left.Y][_top_left.X] = _map.nTile + 1;

                                            break;
                                        }
                                }

                                return true;
                            }
                        }
                        else
                        {
                            for (int collumn = _top_left.X; collumn <= _bottom_right.X; collumn++)
                            {
                                if (_map.mapMatrix[_top_left.Y][collumn] == 43)
                                    _map.mapMatrix[_top_left.Y][collumn] = _map.nTile + 1;

                                if ((_map.mapMatrix[_top_left.Y][collumn] > 0) && (_map.mapMatrix[_top_left.Y][collumn] < _map.nTile)
                                    && (_map.mapMatrix[_top_left.Y][collumn] != _map.nTile - 3))
                                {
                                    switch (_map.mapMatrix[_top_left.Y][collumn])
                                    {
                                        case 40:
                                            {
                                                _map.mapMatrix[_top_left.Y][collumn] = 42;

                                                break;
                                            }
                                        case 41:
                                            {
                                                _map.mapMatrix[_top_left.Y][collumn] = _map.nTile + 1;

                                                break;
                                            }
                                    }

                                    return true;
                                }
                            }
                        }


                        break;
                    }
                case DOWN:
                    {
                        //Lấy tọa độ các góc trên-trái và dưới-phải
                        Point _top_left = new Point((_object.X) / Map.TileSize, _object.Y / Map.TileSize);
                        Point _bottom_right = new Point((_object.X + _object.Width - 5) / Map.TileSize, (_object.Y + _object.Height) / Map.TileSize);

                        if (_top_left.X == _bottom_right.X)
                        {
                            if (_map.mapMatrix[_bottom_right.Y][_bottom_right.X] == 43)
                                _map.mapMatrix[_bottom_right.Y][_bottom_right.X] = _map.nTile + 1;

                            if ((_map.mapMatrix[_bottom_right.Y][_bottom_right.X] > 0) && (_map.mapMatrix[_bottom_right.Y][_bottom_right.X] < _map.nTile)
                                && (_map.mapMatrix[_bottom_right.Y][_bottom_right.X] != _map.nTile - 3))
                                return true;
                        }
                        else
                        {
                            for (int collumn = _top_left.X; collumn <= _bottom_right.X; collumn++)
                            {
                                if (_map.mapMatrix[_bottom_right.Y][collumn] == 43)
                                    _map.mapMatrix[_bottom_right.Y][collumn] = _map.nTile + 1;

                                if ((_map.mapMatrix[_bottom_right.Y][collumn] > 0) && (_map.mapMatrix[_bottom_right.Y][collumn] < _map.nTile)
                                    && (_map.mapMatrix[_bottom_right.Y][collumn] != _map.nTile - 3))
                                    return true;
                            }
                        }

                        break;
                    }
            }
            
            return false;
        }

        //Hàm xử lí thao tác vẽ
        //  1. Tham số truyền vào:
        //      - SpriteBatch _spriteBatch
        //      - GameTime _gameTime
        //  2. Giá trị trả về: Không có
        virtual public void Draw(SpriteBatch _spriteBatch, GameTime _gameTime)
        { 
            //Không xử lí hàm tại đây
        }
    }
}
